#ifndef _SOCKETCONNECTOR_HPP_
#define _SOCKETCONNECTOR_HPP_

#include "jhdefs.hpp"
#include "net/Socket.hpp"
#include "net/SocketAddress.hpp"
#include "net/StreamSocket.hpp"
#include "net/ServerSocket.hpp"
#include "net/SocketReactor.hpp"
#include "net/SocketNotification.hpp"
#include "msg/abstractobserver.hpp"
using JHCPP::msg::TObserver;

NET_NAMESPACE_BEGIN

template <class T>
class TSocketConnector
{
public:		
	explicit TSocketConnector(CSocketAddress& address) : m_pReactor(0)
	{
		m_socket.connectNB(address);
	}

	TSocketConnector(CSocketAddress& address, CSocketReactor& reactor) : m_pReactor(0)
	{
		m_socket.connectNB(address);
		registerConnector(reactor);
	}

	virtual ~TSocketConnector()
	{
		try
		{
			unregisterConnector();
		}
		catch (...)
		{
			jh_unexpected();
		}
	}

	virtual void registerConnector(CSocketReactor& reactor)
	{
		m_pReactor = &reactor;
		m_pReactor->addEventHandler(m_socket, TObserver<SocketConnector, CReadableNotification>(*this, &TSocketConnector::onReadable));
		m_pReactor->addEventHandler(m_socket, TObserver<SocketConnector, CWritableNotification>(*this, &TSocketConnector::onWritable));
		m_pReactor->addEventHandler(m_socket, TObserver<SocketConnector, CErrorNotification>(*this, &TSocketConnector::onError));
	}

	virtual void unregisterConnector()
	{
		if (m_pReactor)
		{
			m_pReactor->removeEventHandler(m_socket, TObserver<TSocketConnector, CReadableNotification>(*this, &TSocketConnector::onReadable));
			m_pReactor->removeEventHandler(m_socket, TObserver<TSocketConnector, CWritableNotification>(*this, &TSocketConnector::onWritable));
			m_pReactor->removeEventHandler(m_socket, TObserver<TSocketConnector, CErrorNotification>(*this, &TSocketConnector::onError));
		}
	}

	void onReadable(CReadableNotification* pNotification)
	{
		pNotification->release();
		int err = m_socket.impl()->socketError(); 
		if (err)
		{
			onError(err);
			unregisterConnector();
		}
		else
		{
			onConnect();
		}
	}

	void onWritable(CWritableNotification* pNotification)
	{
		pNotification->release();
		onConnect();
	}

	void onConnect()
	{
		m_socket.setBlocking(true);
		createServiceHandler();
		unregisterConnector();
	}

	void onError(CErrorNotification* pNotification)
	{
		pNotification->release();
		onError(m_socket.impl()->socketError());
		unregisterConnector();
	}

protected:
	virtual T* createServiceHandler()
	{
		return new T(m_socket, *m_pReactor);
	}

	virtual void onError(int errorCode)
	{
	}

	CSocketReactor* reactor()
	{
		return m_pReactor;
	}

	CStreamSocket& socket()
	{
		return m_socket;
	}

private:
	TSocketConnector();
	TSocketConnector(const TSocketConnector&);
	TSocketConnector& operator = (const TSocketConnector&);

	CStreamSocket   m_socket;
	CSocketReactor* m_pReactor;
};

NET_NAMESPACE_END

#endif
